﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace Useful.GUI
{
    public partial class OptionalTextBox : UserControl
    {
        public event EventHandler ValueChanged;
        public event EventHandler TextValueChanged;

        [FlagsAttribute]
        public enum Kind
        {
            AllowDigites = 1, AllowSign = 2, AllowSpace = 4, AllowDot = 8, AllowComma = 16, AllowEnglishChars = 32, AllowRussianChars = 64, AllowOtherChars = 128, AllowRoundBrace = 512, AllowAt = 1024, AllowUnderlining = 2048, AllowTilde = 4096, AllowSemi = 8192,
                            //Text = AllowDigites | AllowSign | AllowSpace | AllowDot | AllowComma | AllowEnglishChars | AllowRussianChars | AllowOtherChars | AllowUnderlining,
                            Text = AllowDigites | AllowSign | AllowSpace | AllowDot | AllowComma | AllowEnglishChars | AllowRussianChars | AllowOtherChars | AllowRoundBrace | AllowAt | AllowUnderlining | AllowTilde,
                            Long = AllowDigites | AllowSign,
                            Double = AllowDigites | AllowSign | AllowComma,
                            Phone = AllowDigites | AllowSign | AllowSpace | AllowRoundBrace,
                            Email = AllowDigites | AllowSign | AllowSpace | AllowDot | AllowEnglishChars | AllowAt | AllowUnderlining | AllowSemi,
                            Hex = AllowDigites | AllowSpace | AllowEnglishChars,
                            Money = AllowDigites | AllowComma,
                            Default = Text,
                        }

        private Kind textKind = Kind.Default;
        public Kind TextKind
        {
            get
            {
                return textKind;
            }
            set
            {
                textKind = value;
            }
        }

        private ErrorProvider errorProvider = null;
        public ErrorProvider ErrorProvider
        {
            get
            {
                return errorProvider;
            }
            set
            {
                errorProvider = value;
            }
        }

        private string errorText;
        public string ErrorText
        {
            get
            {
                return errorText;
            }
            set
            {
                errorText = value;
            }
        }

        private bool allowEmptyText = true;
        public bool AllowEmptyText
        {
            get
            {
                return allowEmptyText;
            }
            set
            {
                allowEmptyText = value;
            }
        }

        public OptionalTextBox()
        {
            InitializeComponent();
        }

        public bool ProcessValidate()
        {
            bool res = ProcessValidateCore();

            if (errorProvider != null)
                errorProvider.SetError(this, res ? String.Empty : ErrorText);

            return res;
        }

        private bool ProcessValidateCore()
        {
            bool res = false;

            if (cbAvailable.Checked)
            {
                if (!String.IsNullOrEmpty(tbValue.Text))
                {
                    switch (TextKind)
                    {
                        case Kind.Text:
                            break;
                        case Kind.Long:
                            long lRes;
                            res = !long.TryParse(tbValue.Text, out lRes);
                            break;
                        case Kind.Double:
                            double dRes;
                            res = !double.TryParse(tbValue.Text, out dRes);
                            break;
                        case Kind.Hex:
                            long hRes;
                            string hstr = tbValue.Text.Replace(" ",String.Empty);

                            res = true;
                            for(int i = 0; (i < hstr.Length) && res; i += 8)
                            {
                                res = long.TryParse(hstr.Substring(i, Math.Min(8, hstr.Length - i)), System.Globalization.NumberStyles.HexNumber, null, out hRes);
                            }
                            res = !res;
                            break;
                        case Kind.Email:
                            res = !Regex.IsMatch(tbValue.Text, @"^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$");
                            break;
                        case Kind.Phone:
                            res = !Regex.IsMatch(tbValue.Text, @"^(\+[1-9][0-9]*(\([0-9]*\)|-[0-9]*-))?[0]?[1-9][0-9\- ]*$");
                            break;
                    }
                }
                else
                    res = !AllowEmptyText;
            }

            return !res;
        }      

        private void tbValue_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (!Char.IsControl(e.KeyChar))
            {
                if (e.KeyChar == ' ')
                    e.Handled =  (TextKind & Kind.AllowSpace) == 0;

                else if (Char.IsDigit(e.KeyChar))
                    e.Handled = (TextKind & Kind.AllowDigites) == 0;

                else if (e.KeyChar == '.')
                    e.Handled = (TextKind & Kind.AllowDot) == 0;

                else if (e.KeyChar == ',')
                    e.Handled = (TextKind & Kind.AllowComma) == 0;

                else if (e.KeyChar == '@')
                    e.Handled = (TextKind & Kind.AllowAt) == 0;

                else if (e.KeyChar == '_')
                    e.Handled = (TextKind & Kind.AllowUnderlining) == 0;

                else if (e.KeyChar == '~')
                    e.Handled = (TextKind & Kind.AllowTilde) == 0;

                else if (e.KeyChar == '-' || e.KeyChar == '+')
                    e.Handled = (TextKind & Kind.AllowSign) == 0;

                else if (e.KeyChar == '(' || e.KeyChar == ')')
                    e.Handled = (TextKind & Kind.AllowRoundBrace) == 0;

                else if ((e.KeyChar >= 'A' && e.KeyChar <= 'Z') || (e.KeyChar >= 'a' && e.KeyChar <= 'z'))
                    e.Handled = (TextKind & Kind.AllowEnglishChars) == 0;

                else if (e.KeyChar >= 'А' && e.KeyChar <= 'ё')
                    e.Handled = (TextKind & Kind.AllowRussianChars) == 0;

                else if (e.KeyChar == ';')
                    e.Handled = (TextKind & Kind.AllowSemi) == 0;

                else
                    e.Handled = (TextKind & Kind.AllowOtherChars) == 0;
            }
        }

        public bool Avaiable
        {
            get
            {
                return cbAvailable.Checked;
            }
            set
            {
                cbAvailable.Checked = value;
            }
        }

        public override string Text
        {
            get
            {
                return Avaiable ? tbValue.Text : null;
            }
            set
            {
                tbValue.Text = value;

                cbAvailable.Checked = value != null;
            }
        }

        public string Caption
        {
            get
            {
                return gbCaption.Text;
            }
            set
            {
                gbCaption.Text = value;
            }
        }

        public GroupBox GroupBoxControl
        {
            get
            {
                return gbCaption;
            }
        }

        public TextBox TextBoxControl
        {
            get
            {
                return tbValue;
            }
        }

        public CheckBox CheckBoxControl
        {
            get
            {
                return cbAvailable;
            }
        }

        private void cbAvailable_CheckedChanged(object sender, EventArgs e)
        {
            tbValue.ReadOnly = !cbAvailable.Checked;

            if (!(cbAvailable.Checked && String.IsNullOrEmpty(tbValue.Text)))
            {
                if (errorProvider != null)
                    errorProvider.SetError(this, ProcessValidateCore() ? String.Empty : ErrorText);
            }

            if (cbAvailable.Checked)
                tbValue.Select();

            if (ValueChanged != null)
                ValueChanged(this, EventArgs.Empty);
        }

        public bool DisplayCheckBox
        {
            get
            {
                return cbAvailable.Visible;
            }
            set
            {
                cbAvailable.Visible = value;
            }
        }

        protected override void OnLeave(EventArgs e)
        {
            if (!String.IsNullOrEmpty(tbValue.Text))
            {
                if (errorProvider != null)
                    errorProvider.SetError(this, ProcessValidateCore() ? String.Empty : ErrorText);
            }

            if (ValueChanged != null)
                ValueChanged(this, EventArgs.Empty);

            base.OnLeave(e);
        }

        public bool ReadOnly
        {
            get
            {
                return tbValue.ReadOnly;
            }
            set
            {
                tbValue.ReadOnly = value;
            }
        }

        public string TrimmedText
        {
            get
            {
                string res = null;

                if (Avaiable)
                {
                    string str = tbValue.Text.Trim();

                    if (!String.IsNullOrEmpty(str))
                        res = str;
                }

                return res;
            }
            set
            {
                tbValue.Text = value;
            }
        }

        public string TrimmedText2
        {
            get
            {
                if (Avaiable)
                    return tbValue.Text.Trim();
                else
                    return null;
            }
        }

        public T GetValue<T>()
        {
            string str = TrimmedText;

            if (str != null)
                return (T)Convert.ChangeType(str, typeof(T));
            else
                return default(T);
        }

        public void SelectControl()
        {
            Select();
            TextBoxControl.SelectionStart = 0;
            TextBoxControl.SelectionLength = 0;
        }

        public void SetToolTip(ToolTip toolTip, string str)
        {
            toolTip.SetToolTip(GroupBoxControl, str);
            toolTip.SetToolTip(TextBoxControl, str);
            toolTip.SetToolTip(CheckBoxControl, str);
        }

        private void tbValue_TextChanged(object sender, EventArgs e)
        {
            if (TextValueChanged != null)
                TextValueChanged(this, EventArgs.Empty);
        }
    }
}
